package com.chen.paymentdemo.controller;

import com.chen.paymentdemo.service.WxPayService;
import com.chen.paymentdemo.util.HttpUtils;
import com.chen.paymentdemo.util.WechatPay2ValidatorForRequest;
import com.chen.paymentdemo.vo.R;
import com.google.gson.Gson;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Y·C
 * @version 1.0.0
 * @ClassName WxPayController.java
 * @Description TODO
 * @createTime 2023年07月19日 23:22:00
 */
@CrossOrigin
@RestController
@RequestMapping("/api/wx-pay")
@Api(tags = "网站微信支付API")
@Slf4j
public class WxPayController {

    @Resource
    private WxPayService wxPayService;

    // 获取签名验证器
    @Resource
    private Verifier verifier;


    /**
    * 第一步：调用统一下单API，生成支付订单二维码
    * */
    @ApiOperation("调用统一下单API，生成支付订单二维码")
    @PostMapping("/native/{productId}")
    public R nativePay(@PathVariable Long productId) throws Exception {


        log.info("发起支付请求，商品ID：{}", productId);

        // 返回支付二维码连接和订单号
         Map<String,Object> map = wxPayService.nativePay(productId);

        return R.ok().setData(map);
    }


    /**
     * 第二步：支付回调通知
     *
     * 通知规则：用户支付完成后，微信会把相关支付结果和用户信息发送给商户，商户需要接收处理
     * 该消息，并返回应答。对后台通知交互时，如果微信收到商户的应答不符合规范或超时，微信认
     * 为通知失败，微信会通过一定的策略定期重新发起通知，尽可能提高通知的成功率，但微信不保
     * 证通知最终能成功。（通知频率为
     * 15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 总计 24h4m）
     * */
    @ApiOperation("支付回调通知")
    @PostMapping("/native/notify")
    public String nativeNotify(HttpServletRequest request, HttpServletResponse response){
        log.info("支付回调通知");
        Gson gson = new Gson();
        Map<String,String> map = new HashMap<>(); //应答对象

        //处理通知参数
        try {
            //读取通知数据
            String body = HttpUtils.readData(request);
            Map<String,Object> bodyMap = gson.fromJson(body, HashMap.class);
            String requestId = (String) bodyMap.get("id");
            log.info("支付通知的id====>{}",bodyMap.get("id"));
            log.info("支付通知的完整数据====>{}",body);

            //TODO : 签名的验证
            WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest =
                    new WechatPay2ValidatorForRequest(verifier, requestId, body);
            if (!wechatPay2ValidatorForRequest.validate(request)){
                log.info("签名验证失败");
                //失败应答
                response.setStatus(500);
                map.put("code","ERROR");
                map.put("message","失败");
                return gson.toJson(map);
            }
            log.info("签名验证成功");

            //TODO : 处理订单
            wxPayService.processOrder(bodyMap);

            //应答超时
            //模拟接受微信支付通知后，业务处理时间过长，微信支付会发起重试通知
//            TimeUnit.SECONDS.sleep(5);

            //成功应答
            response.setStatus(200);
            map.put("code","SUCCESS");
            map.put("message","成功");

            return gson.toJson(map);
        } catch (Exception e) {
            e.printStackTrace();

            //失败应答
            response.setStatus(500);
            map.put("code","ERROR");
            map.put("message","失败");
            return gson.toJson(map);
        }

    }

    /**
     * 第三步：取消订单 接口
     * */
    @ApiOperation("取消订单")
    @PostMapping("/cancel/{orderNo}")
    public R cancel(@PathVariable String orderNo) throws Exception {
        log.info("取消订单，订单号：{}",orderNo);
        wxPayService.cancelOrder(orderNo);

        return R.ok().setMsg("取消订单成功");
    }

    /**
     * 第四步：查询支付订单
     * */

    @GetMapping("/query/{orderNo}")
    @ApiOperation("查询支付订单")
    public R queryOrder(@PathVariable String orderNo) throws Exception {

        log.info("查询支付订单");
        String result = wxPayService.queryOrder(orderNo);
        return R.ok().setMsg("查询支付订单成功").data("result",result);

    }

    /**
     * 第五步：申请退款
     * */
    @ApiOperation("申请退款")
    @PostMapping("/refunds/{orderNo}/{reason}")
    public R refunds(@PathVariable String orderNo,@PathVariable String reason) throws Exception {
        log.info("申请退款");
        wxPayService.refund(orderNo,reason);
        return R.ok().setMsg("申请退款成功");
    }



    /**
     * 第六步： 查询退款
     * @param refundNo
     * @return
     * @throws Exception
     */
    @ApiOperation("查询退款：测试用")
    @GetMapping("/query-refund/{refundNo}")
    public R queryRefund(@PathVariable String refundNo) throws Exception {

        log.info("查询退款");

        String result = wxPayService.queryRefund(refundNo);
        return R.ok().setMsg("查询成功").data("result", result);
    }


    /**
     * 第七步： 退款结果通知
     * 退款状态改变后，微信会把相关退款结果发送给商户。
     */
    @ApiOperation("退款结果通知")
    @PostMapping("/refunds/notify")
    public String refundsNotify(HttpServletRequest request, HttpServletResponse response){

        log.info("退款通知执行");
        Gson gson = new Gson();
        Map<String, String> map = new HashMap<>();//应答对象

        try {
            //处理通知参数
            String body = HttpUtils.readData(request);
            Map<String, Object> bodyMap = gson.fromJson(body, HashMap.class);
            String requestId = (String)bodyMap.get("id");
            log.info("支付通知的id ===> {}", requestId);

            //签名的验证
            WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest
                    = new WechatPay2ValidatorForRequest(verifier, requestId, body);
            if(!wechatPay2ValidatorForRequest.validate(request)){

                log.error("通知验签失败");
                //失败应答
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "通知验签失败");
                return gson.toJson(map);
            }
            log.info("通知验签成功");

            //处理退款单
            wxPayService.processRefund(bodyMap);

            //成功应答
            response.setStatus(200);
            map.put("code", "SUCCESS");
            map.put("message", "成功");
            return gson.toJson(map);

        } catch (Exception e) {
            e.printStackTrace();
            //失败应答
            response.setStatus(500);
            map.put("code", "ERROR");
            map.put("message", "失败");
            return gson.toJson(map);
        }
    }

    @ApiOperation("获取账单url，测试用")
    @GetMapping("/querybill/{billDate}/{type}")
    public R queryBill(@PathVariable String billDate,
                       @PathVariable String type) throws Exception {
        log.info("获取账单url");

        String downloadUrl = wxPayService.queryBill(billDate, type);
        return R.ok().setMsg("获取账单url成功").data("downloadUrl", downloadUrl);
    }

    /**
     * 第八步：下载账单
     * */
    @ApiOperation("下载账单")
    @GetMapping("/downloadbill/{billDate}/{type}")
    public R downloadBill(
            @PathVariable String billDate,
            @PathVariable String type) throws Exception {

        log.info("下载账单");
        String result = wxPayService.downloadBill(billDate, type);

        return R.ok().data("result", result);
    }



}
